/**
 * TabVD is a Virtual Desktop Client/Server designed specifically for connecting
 * from Tablet like devices.
 *
 * Copyright (C) 2011 Subhabrata Ghosh
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * DbInstaller.java
 *
 *  Created on: Jul 10, 2011
 *      Author: subhagho
 */
package net.langene.tabvd.core.db;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.Statement;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.langene.tabvd.core.XMLHelper;
import net.langene.tabvd.core.db.Schema.Column;
import net.langene.tabvd.core.db.Schema.Table;

/**
 * @author subhagho
 * 
 */
public class DbInstaller {
	private static final Logger logger = LoggerFactory
			.getLogger(DbInstaller.class);

	private static final String _DB_RESOURCE_XML_ = "/net/langene/tabvd/data/db/dbsetup.xml";

	private Connection _dbconn;
	private XMLHelper _helper = null;
	private Schema _schema = null;

	/**
	 * net.langene.tabvd.core.db.DbInstaller
	 * 
	 * @param conn
	 * @throws Exception
	 */
	public DbInstaller(Connection conn) throws Exception {
		this._dbconn = conn;
	}

	/**
	 * Get the Database setup.
	 * 
	 * net.langene.tabvd.core.db.DbInstaller
	 * 
	 * @throws Exception
	 */
	public Schema checkSetup() throws Exception {
		InputStream stream = DbInstaller.class
				.getResourceAsStream(_DB_RESOURCE_XML_);
		_helper = new XMLHelper(stream);
		_schema = DBHelper.loadSchema(_helper);
		logger.debug(_schema.toString());
		Schema dbschema = DBHelper.loadDbSchema(_dbconn);
		if (!isValidSchema(dbschema, _schema)) {
			createSchema();
		}
		return _schema;
	}

	/**
	 * Create the Database Schema.
	 * 
	 * net.langene.tabvd.core.db.DbInstaller
	 * 
	 * @throws Exception
	 */
	public void createSchema() throws Exception {
		for (String key : _schema.Tables.keySet()) {
			Table table = _schema.Tables.get(key);
			String dsql = table.getDropSql();
			logger.debug("Dropping table [" + table.Name + "] [" + dsql + "]");
			Statement stmnt = _dbconn.createStatement();
			stmnt.execute(dsql);
			String csql = table.getCreateSql();
			logger.debug("Creating table [" + table.Name + "] [" + csql + "]");
			stmnt.execute(csql);
			stmnt.close();
		}
	}

	/**
	 * Check is the Database Schema has been created and if it is valid.
	 * 
	 * net.langene.tabvd.core.db.DbInstaller
	 * 
	 * @return
	 * @throws Exception
	 */
	public boolean isValidSchema(Schema dbschema, Schema xschema)
			throws Exception {
		for (String key : xschema.Tables.keySet()) {
			logger.debug("Looking for table [" + key + "]");
			if (!dbschema.Tables.containsKey(key)) {
				logger.warn("Table not found [" + key + "]");
				return false;
			}
			Table dtable = dbschema.Tables.get(key);
			Table xtable = xschema.Tables.get(key);
			if (!compareTables(xtable, dtable)) {
				logger.warn("Invalid table definition, columns don't match ["
						+ key + "]");
				return false;
			}
		}
		return true;
	}

	private boolean compareTables(Table xtable, Table dtable) {
		for (Column xcol : xtable.Columns) {
			boolean found = false;
			for (Column dcol : dtable.Columns) {
				if (xcol.Name.compareToIgnoreCase(dcol.Name) == 0) {
					if (xcol.Type == dcol.Type) {
						found = true;
					}
					break;
				}
			}
			if (!found)
				return false;
		}
		return true;
	}
}
